package com.mxf.code.redisson_demo;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * Redisson分布式锁实现-使用可重入非公平锁（RedissonLock）
 */
@Component
@Slf4j
public class RedissonDistributedLocker implements DistributedLocker {
	@Autowired
    private RedissonClient redissonClient;

	public RLock lock(String lockKey) {
        RLock lock = this.redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

	public RLock lock(String lockKey, long timeout) {
        RLock lock = this.redissonClient.getLock(lockKey);
        lock.lock(timeout, TimeUnit.SECONDS);
        return lock;
    }

	public RLock lock(String lockKey, TimeUnit unit, long timeout) {
        RLock lock = this.redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }
    /**
     *使用定义的leaseTime获取锁。必要时等待，直到锁可用。锁定将在定义的租赁时间间隔后自动释放。
     * 参数： leaseTime–如果尚未通过调用unlock释放锁，则获取锁后保持锁的最长时间。
     *        如果leaseTime为-1，请保持锁定直到明确解锁。
     * unit–时间单位 投掷次数： InterruptedException–如果线程被中断
     */
	public boolean tryLock(String lockKey, TimeUnit unit, long leaseTime) {
        RLock lock = this.redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(0L, leaseTime, unit);
        } catch (InterruptedException var7) {
            return false;
        }
    }


	public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime){
		RLock lock = redissonClient.getLock(lockKey);
		try {
	    	return lock.tryLock(waitTime, leaseTime, unit);
	    } catch (InterruptedException e) {
			return false;
		}
	}
	
	public void unlock(String lockKey){
	    RLock lock = redissonClient.getLock(lockKey);
	    try {
	        if (lock.isLocked()) {
	            lock.unlock();
	        }
	    } catch (IllegalMonitorStateException localIllegalMonitorStateException) {}
	}

	public void unlock(RLock lock) {
        try {
            if (lock.isLocked()) {
                lock.unlock();
            }
        } catch (IllegalMonitorStateException var3) {}
    }

    @Override
    public <T> T tryLockAndRun(@Nonnull String lockKey, @Nonnull TimeUnit unit, long waitTime, long leaseTime, @Nonnull Supplier<T> supplier, String scene) {
        final long start = System.currentTimeMillis();
        // 获取分布式锁，最长等待时间:10秒,20秒后自动释放。注意锁与事务的顺序：获取分布式锁 -> 开启事务 -> 执行业务 -> 提交事务 -> 释放分布式锁！！！
        final boolean tryLock = this.tryLock(lockKey, unit, waitTime, leaseTime);
        final long end = System.currentTimeMillis();
        if (!tryLock) {
            log.error("[{}]获取分布式锁失败，lockKey = {}，耗时{}ms", scene, lockKey, end - start);
            throw new RuntimeException("加锁失败");
        }

        // 注意：一定是获取锁成功后，才进行try{}finally{释放锁}
        try {
            log.info("[{}]获取分布式锁成功，lockKey = {}，耗时{}ms", scene, lockKey, end - start);
            return supplier.get();
        } finally {
            this.unlock(lockKey);
        }
    }
}
